use std::{
    collections::HashMap,
    sync::{Arc, Mutex, RwLock},
};

use model_graph_types::peer::get_peer_id;
use rand::Rng;
use tokio::time::{sleep, timeout, Duration};

use super::{message::Message, request::request_response};

lazy_static::lazy_static! {
    //
    pub(crate) static ref RESPONSE_BUFFER: RwLock<HashMap<u32, Option<String>>> = RwLock::new(HashMap::new());
    ///
    pub(crate) static ref CALLBACKS: RwLock<Option<Arc<Mutex<Box<dyn Fn(u32, String, String) + Send + Sync>>>>> = RwLock::new(None);
}

pub async fn remote_request(
    peer_id: String,
    message_str: String,
    timout: u64,
) -> anyhow::Result<String> {
    tracing::debug!("remote_request{}:{}", peer_id, message_str);

    let local_peer_id = get_peer_id()?;
    if local_peer_id == peer_id {
        //自身
        let response = ui_request_response(&peer_id, message_str, timout).await?;
        tracing::debug!("local_request返回:{}", response);
        Ok(response)
    } else {
        //
        let message = Message::uicmd(message_str.into_bytes());
        let response = String::from_utf8(request_response(&peer_id, message, timout).await?.data)
            .map_err(|err| anyhow::anyhow!("{}", err))?;
        tracing::debug!("remote_request返回:{}", response);
        Ok(response)
    }
}

pub async fn ui_request_response(
    peer_id: &String,
    message: String,
    time_out: u64,
) -> anyhow::Result<String> {
    //获取sender
    tracing::debug!("开始请求.....",);
    if let Ok(response_result) = timeout(
        Duration::from_millis(time_out),
        Box::pin(async move {
            //发送结果
            _response(peer_id, message).await
        }),
    )
    .await
    {
        let response = response_result.map_err(|err| anyhow::anyhow!("{}", err))?;
        tracing::debug!("返回数据成功!");
        return Ok(response);
    } else {
        tracing::debug!("请求超时!");
        return Err(anyhow::anyhow!("请求超时!"));
    }
}

async fn _response(peer_id_1: &String, message: String) -> anyhow::Result<String> {
    //设置一个
    let request_id = generate_push_request_id()?;
    let peer_id = peer_id_1.clone();
    tracing::debug!("请求ID:{}", request_id);

    //获取callback
    if let Ok(Some(callback)) = get_on_message_callback() {
        //
        callback.lock().map_err(|err| anyhow::anyhow!("{}", err))?(request_id, peer_id, message);
    } else {
        //发送失败
        let _ = remove_response(request_id).await;
        return Err(anyhow::anyhow!("没有获取到回到函数!"));
    }
    //发送成功,循环进行等待结果
    loop {
        let pop_res = pop_response(request_id).await;
        match pop_res {
            Ok(res_message) => {
                if let Some(response) = res_message {
                    //获取到返回值
                    return Ok(response);
                } else {
                    //
                    sleep(Duration::from_millis(10)).await;
                }
            }
            Err(err) => {
                let _ = remove_response(request_id).await;
                return Err(anyhow::anyhow!("{}", err));
            }
        }
    }
}

pub fn generate_push_request_id() -> anyhow::Result<u32> {
    //随机一个值
    let mut rng = rand::thread_rng();

    let mut request_id: u32 = rng.gen();
    while !push_response(request_id)? {
        request_id = rng.gen();
    }
    Ok(request_id)
}

fn push_response(request_id: u32) -> anyhow::Result<bool> {
    //判断是否存在
    let exist = {
        let cache = RESPONSE_BUFFER
            .read()
            .map_err(|err| anyhow::anyhow!("{}", err))?;
        cache.contains_key(&request_id)
    };
    if exist {
        Ok(false)
    } else {
        //
        let mut cache_result = RESPONSE_BUFFER
            .write()
            .map_err(|err| anyhow::anyhow!("获取锁失败:{}", err))?;

        cache_result.insert(request_id, None);
        tracing::debug!("插入成功!");
        Ok(true)
    }
}

async fn pop_response(request_id: u32) -> anyhow::Result<Option<String>> {
    //
    let mut cache_result = RESPONSE_BUFFER
        .write()
        .map_err(|err| anyhow::anyhow!("获取锁失败:{}", err))?;
    if let Some(message) = cache_result.get(&request_id) {
        if message.is_some() {
            if let Some(message) = cache_result.remove(&request_id) {
                Ok(message)
            } else {
                Err(anyhow::anyhow!("不存在该请求id!{}", request_id))
            }
        } else {
            Ok(None)
        }
    } else {
        Err(anyhow::anyhow!("不存在该请求id!{}", request_id))
    }
}

async fn remove_response(request_id: u32) -> anyhow::Result<Option<String>> {
    //
    let mut cache_result = RESPONSE_BUFFER
        .write()
        .map_err(|err| anyhow::anyhow!("获取锁失败:{}", err))?;
    if let Some(message) = cache_result.remove(&request_id) {
        Ok(message)
    } else {
        Ok(None)
    }
}

pub async fn put_response(request_id: u32, response: String) -> anyhow::Result<()> {
    //
    let mut cache_result = RESPONSE_BUFFER
        .write()
        .map_err(|err| anyhow::anyhow!("获取锁失败:{}", err))?;
    if let Some(message) = cache_result.get_mut(&request_id) {
        *message = Some(response);
        Ok(())
    } else {
        Err(anyhow::anyhow!("不存在该请求id!{}", request_id))
    }
}

pub fn set_on_message_callback(
    callback: Box<dyn Fn(u32, String, String) + Send + Sync>,
) -> anyhow::Result<()> {
    let cache_result = CALLBACKS
        .write()
        .map_err(|err| anyhow::anyhow!("获取锁失败:{}", err));

    match cache_result {
        Ok(mut cache) => {
            *cache = Some(Arc::new(Mutex::new(callback)));
            tracing::debug!("set_on_message_callback成功!");
            Ok(())
        }
        Err(err) => {
            tracing::debug!("set_on_message_callback失敗!{}", err);
            Ok(())
        }
    }
}

fn get_on_message_callback(
) -> anyhow::Result<Option<Arc<Mutex<Box<dyn Fn(u32, String, String) + Send + Sync>>>>> {
    let cache_result = CALLBACKS
        .read()
        .map_err(|err| anyhow::anyhow!("获取锁失败:{}", err));

    match cache_result {
        Ok(cache) => Ok(cache.clone()),
        Err(err) => {
            tracing::debug!("get_on_message_callback失敗!{}", err);
            Err(anyhow::anyhow!("{}", err))
        }
    }
}
